package com.aloha.boot03.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.List;

/**
 * @author DaiZhiHeng
 * @date 2023/10/9 21:14
 */
@Controller
public class ProxyController {

    private final Logger log = LoggerFactory.getLogger(ProxyController.class);

    @Value("${proxy.url}")
    private String proxyUrl;

    @Value("${proxy.tag}")
    private String proxyTag;

    @Resource
    private RemoteProxyUtils remoteProxyUtils;

    @RequestMapping("${proxy.path}")
    public ResponseEntity<?> proxy(HttpServletRequest request) {
        String url = proxyUrl + request.getRequestURI().replace(proxyTag, "");
        try {
            ResponseEntity<?> responseEntity = remoteProxyUtils.doRemoteProxy(request, url);
            return responseEntity;
        } catch (Exception e) {
            log.error("请求路径: {} 时发生错误", url);
            throw new RuntimeException(e.getMessage());
        }
    }

    @Component
    public static class RemoteProxyUtils {

        @Resource
        private RestTemplate restTemplate;

        public ResponseEntity<?> doRemoteProxy(HttpServletRequest request, String url) throws Exception {
            String queryString = request.getQueryString();
            if (StringUtils.hasText(queryString)) {
                url = url + "?" + queryString;
            }
            return route(createRequestEntity(request, url));
        }

        /**
         * 构造转发的请求参数
         */
        private RequestEntity<?> createRequestEntity(HttpServletRequest request, String url) throws Exception {
            // 1.请求体
            byte[] body = parseRequestBody(request);

            // 2.请求头
            MultiValueMap<String, String> headers = parseRequestHeader(request);

            // 3.请求方法
            HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());

            // 4.URI
            URI uri = new URI(url);

            return new RequestEntity<>(body, headers, httpMethod, uri);
        }

        /**
         * 解析请求头
         */
        private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
            HttpHeaders headers = new HttpHeaders();
            List<String> headerNames = Collections.list(request.getHeaderNames());
            for (String headerName : headerNames) {
                List<String> headerValues = Collections.list(request.getHeaders(headerName));
                for (String headerValue : headerValues) {
                    headers.add(headerName, headerValue);
                }
            }
            return headers;
        }

        /**
         * 解析请求体
         */
        private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
            return StreamUtils.copyToByteArray(request.getInputStream());
        }

        /**
         * 路由请求
         */
        private ResponseEntity<?> route(RequestEntity<?> requestEntity) {
            return restTemplate.exchange(requestEntity, Object.class);
        }
    }

}
